/*
* This file is a part of the open-eBackup project.
* This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
* If a copy of the MPL was not distributed with this file, You can obtain one at
* http://mozilla.org/MPL/2.0/.
*
* Copyright (c) [2024] Huawei Technologies Co.,Ltd.
*
* THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
* EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
* MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
*/
#ifndef VOLUMEBACKUP_VOLUME_COPY_MOUNT_PROVIDER_HEADER
#define VOLUMEBACKUP_VOLUME_COPY_MOUNT_PROVIDER_HEADER

#include "common/VolumeProtectMacros.h"

#ifdef _MSC_VER

#define RECORD_INNER_ERROR(format, ...) do { \
    RecordError(format, __VA_ARGS__); \
    ERRLOG(format, __VA_ARGS__); \
} while (0) \

#else

#define RECORD_INNER_ERROR(format, args...) do { \
    RecordError(format, ##args); \
    ERRLOG(format, ##args); \
} while (0) \

#endif

constexpr uint16_t NUMBER_ZERO = 0;
constexpr uint32_t MAX_ERR_MSG_SIZE = 4096; // 1024*4

namespace volumeprotect {
/**
 * @brief volume copy mount module
 */
namespace mount {

struct VolumeCopyMountConfig {
    ///> Where files generated by mounting process created
    std::string     outputDirPath;
    ///> Requiring a copy name to decide the name of copy meta json
    std::string     copyName;
    ///> Directory path of the volume copy meta
    std::string     copyMetaDirPath;
    ///> Directory path of the volume copy data
    std::string     copyDataDirPath;
    ///> used for VHFX compare
    std::string     shareName;
    ///> Mount target path.
    ///> For *nix loopback mount, the target directory must be created head
    ///> For Windows virtual disk mount, it can keep empty to retrieve a drive letter automatically
    std::string     mountTargetPath;

    bool            readOnly;

    // [Optional] fields....
    ///> Only used for *unix mount to sepecify filesystem type (option "-t", eg: ext4, xfs, btrfs...)
    std::string     mountFsType;
    ///> Only used for *unix mount to sepecify mount options (option "-o", eg: "ro,loop,noatime")
    std::string     mountOptions;
};

/**
 * @brief Define a inner logger to track the errors occured in mount/umount routines.
 * This should be necessary, for this module may be provided as an independent dynamic lib for extensions
 * like CPython or JNI to invoke, inner logger may track and save the error info for debugging without
 * 3rd logger module being used.
 */
class VOLUMEPROTECT_API InnerErrorLoggerTrait {
public:
    ///> Get all errors as a string splited by "\n"
    std::string GetError() const;
    ///> Get all errors as a vector
    std::vector<std::string> GetErrors() const;

protected:
    ///> format an error log to for tracking
    void RecordError(const char* message, ...);

private:
    std::vector<std::string> m_errors;
};

/**
 * @brief Function as base class for multple volume copy mount provider of different backup format.
 * Mount process takes a configuration from VolumeCopyMountConfig and may generate some magic file in outputDirPath
 * Mounting process:
 *   1. validate directory path : outputDirPath, copyMetaDirPath, copyDataDirPath and mountTargetPath
 *   2. read copy meta json file with specified copyName and copyMetaDirPath
 *   3. extract copyMeta struct from json file content to decide which mount provider to load
 *   4. mount copy using corresponding provider
 *   5. save the mount record file to outputDirPath
 */
class VOLUMEPROTECT_API VolumeCopyMountProvider : public InnerErrorLoggerTrait {
public:
    /**
     * @brief Builder function to load target copy mount provider, depending on which CopyFormat specified.
     * @param mountConfig
     * @return a valid `std::unique_ptr<VolumeCopyMountProvider>` ptr if succeed
     * @return `nullptr` if failed
     */
    static std::unique_ptr<VolumeCopyMountProvider> Build(
        const VolumeCopyMountConfig& mountConfig);

    virtual ~VolumeCopyMountProvider() = default;

    /**
     * @brief Perform mount operation.
     * @return `true` if succeed, `false` if failed.
     */
    virtual bool Mount();

    /**
     * @brief Used to get mount record file path if `Mount` operation is succeed.
     * @return the absolute json file path of the mount record file
     */
    virtual std::string GetMountRecordPath() const;

};

/**
 * @brief Function as base class for multple volume copy umount provider of different backup format.
 * Umount process read config from mountRecordJsonFilePath json file
 * Umount process:
 *   1. validate json file mountRecordJsonFilePath and read mount record info
 *   2. deciding which umount provider to load
 *   3. umount copy using corresponding umount provider
 */
class VOLUMEPROTECT_API VolumeCopyUmountProvider : public InnerErrorLoggerTrait {
public:
    /**
     * @brief Builder function to build a corresponding umount provider from specified json record file
     * @param mountRecordJsonFilePath
     * @return a valid `std::unique_ptr<VolumeCopyUmountProvider>` ptr if succeed
     * @return `nullptr` if failed
     */
    static std::unique_ptr<VolumeCopyUmountProvider> Build(
        const std::string mountRecordJsonFilePath,
        const std::string& shareName = "");

    virtual ~VolumeCopyUmountProvider() = default;

    /**
     * @brief Perform umount operation.
     * @return `true` if succeed, `false` if failed.
     */
    virtual bool Umount();
};

}
}

#endif